﻿using Musi.Core.CSV;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace Musi
{
    [System.Serializable]
    public class Chart: IEnumerable
    {
        protected ChartPreview chartPreview;
        public List<ChartNote> chartNotes;

        public ChartSong Song => chartPreview.Song;
        public string ChartName => chartPreview.Name;
        public string ChartMaker => chartPreview.Maker;
        public ChartTime ChartLength => chartPreview.Length;
        public int Level => chartPreview.Level;
        public ChartPreview ChartPreview { get => chartPreview; set { chartPreview = value; } }

        public List<ChartNote> ChartNotes => chartNotes;
        
        public Chart()
        {
            chartNotes = new List<ChartNote>();
            chartPreview = new ChartPreview();
        }

        public Chart(ChartPreview chartPreview)
        {
            chartNotes = new List<ChartNote>();
            this.chartPreview = chartPreview;
        }

        public Chart(ChartSong song, string name, string maker, ChartTime length, int level)
        {
            chartNotes = new List<ChartNote>();
            chartPreview = new ChartPreview
            {
                Song = song,
                Name = name,
                Maker = maker,
                Length = length,
                Level = level
            };
        }

        public void AddChartNote(ChartNote note)
        {
            chartNotes.Add(note);
        }

        public void AddChartNotes(ChartNote[] notes)
        {
            chartNotes.AddRange(notes);
        }

        public void SortChartNotes()
        {
            chartNotes.Sort();
        }

        public void RemoveChartNotes(ChartNote note)
        {
            chartNotes.Remove(note);
        }

        public ChartNote[] GetNote(ChartTime time)
        {
            List<ChartNote> targetNote = new List<ChartNote>();
            foreach(ChartNote chartNote in chartNotes)
            {
                if(chartNote.startTime.Equals(time))
                {
                    targetNote.Add(chartNote);
                }
            }
            return targetNote.ToArray();
        }

        public Chart Clone()
        {
            Chart chart = new Chart(this.chartPreview);
            chart.AddChartNotes(this.ChartNotes.ToArray());
            return chart;
        }

        #region Setter
        public void SetSongName(string songName)
        {
            chartPreview.Name = songName;
        }

        public void SetSongPath(string path)
        {
            chartPreview.SetSongPath(path);
        }

        public void SetChartName(string newName)
        {
            chartPreview.Name = newName;
        }

        public void SetChartMaker(string newMaker)
        {
            chartPreview.Maker = newMaker;
        }

        public void SetChartLength(ChartTime newLength)
        {
            chartPreview.Length = newLength;
        }

        public void SetChartLevel(int level)
        {
            chartPreview.Level = level;
        }
        #endregion

        #region Static Method
        public static Chart ParsePreview(Chart chart, CSVParser csvParser)
        {
            chart.ChartPreview = ChartPreview.GetFromCSV(csvParser);

            return chart;
        }

        public static Chart ParseNote(Chart chart, CSVParser csvParser)
        {
            (int, int) pos = csvParser.Find("[=[Notes]=]");

            for (int i = pos.Item1 + 1; i < csvParser.Row; i++)
            {
                ChartNote note = csvParser.ParseList<ChartNote>(i).Unwarp();
                if (note != null)
                {
                    chart.AddChartNote(note);
                }
            }
            return chart;
        }

        public static Chart ParseSource(CSVParser csvParser)
        {
            if (csvParser == null)
                return null;

            Chart chart = new Chart();

            ParsePreview(chart, csvParser);

            ParseNote(chart, csvParser);

            #region Debug Data Out
            StringBuilder str = new StringBuilder();

            for (int i = 0; i < csvParser.Row; i++)
            {
                str.Append($"Row{i}: ");
                for (int j = 0; j < csvParser[i].Length; j++)
                {
                    str.Append(csvParser[i][j]);
                    if (j != csvParser[i].Length - 1)
                    {
                        str.Append(",");
                    }
                }
                if (i != csvParser.Row)
                {
                    str.Append("\n");
                }
            }
            Debug.Log(str.ToString());
            #endregion

            return chart;
        }
        #endregion

        #region Iterator
        public IEnumerator GetEnumerator()
        {
            return new Enumrator(chartNotes.ToArray());
        }

        public class Enumrator : IEnumerator
        {
            private ChartNote[] notes;
            private int position = -1;
            public object Current
            {
                get
                {
                    if (position >= notes.Length)
                        return null;
                    return notes[position];
                }
            }

            public Enumrator(ChartNote[] notes)
            {
                this.notes = notes;
            }

            public bool MoveNext()
            {
                if(position < notes.Length)
                {
                    position++;
                    return true;
                }
                return false;
            }

            public void Reset()
            {
                position = -1;
            }
        }
        #endregion
    }
}
